package site.xuxingcan;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class HttpServerHandlerInterface extends ChannelInboundHandlerAdapter {
    public static final Gson gson = new Gson();
    private HttpPostRequestDecoder decoder;
    private HashMap<String, String> hashMap;

    public abstract void onGetRequest(ChannelHandlerContext ctx, HashMap<String, String> parHashMap) throws Exception;

    public abstract void onPostRequest(ChannelHandlerContext ctx, HashMap<String, String> parHashMap) throws Exception;

    public void writeAndFlushResponse(ChannelHandlerContext ctx, int code, String msg) throws UnsupportedEncodingException {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("result", code);
        jsonObject.addProperty("data", msg);
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK, Unpooled.wrappedBuffer(jsonObject.toString().getBytes("UTF-8")));
        response.headers().set(io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE, "text/plain");
        response.headers().set(io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes());
        response.headers().set(io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        ctx.writeAndFlush(response);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;
            if (HttpMethod.POST.equals(request.method())) {
                decoder = new HttpPostRequestDecoder(request);
                hashMap = new HashMap<>();
            } else {
                decoder = null;
                hashMap = new HashMap<>();
                QueryStringDecoder decoderQuery = new QueryStringDecoder(request.uri());
                Map<String, List<String>> uriAttributes = decoderQuery.parameters();
                for (Map.Entry<String, List<String>> attr : uriAttributes.entrySet()) {
                    for (String attrVal : attr.getValue()) {
                        hashMap.put(attr.getKey(), attrVal);
                    }
                }
//				for (HashMap.Entry<String, String> entry : hashMap.entrySet()) {
//					System.out.println(entry.getKey() + " = " + entry.getValue());
//				}
                onGetRequest(ctx, hashMap);
            }
        } else if (msg instanceof HttpContent && decoder != null) {
            HttpContent content = (HttpContent) msg;
            decoder.offer(content);
            try {
                while (decoder.hasNext()) {
                    InterfaceHttpData data = decoder.next();
                    if (data != null) {
                        try {
                            if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
                                Attribute attribute = (Attribute) data;
                                hashMap.put(attribute.getName(), attribute.getValue());
                            }
                        } finally {
                            data.release();
                        }
                    }
                }
            } catch (HttpPostRequestDecoder.EndOfDataDecoderException e) {
//				e.printStackTrace();
            }
            if (content instanceof LastHttpContent) {
//				for (HashMap.Entry<String, String> entry : hashMap.entrySet()) {
//					System.out.println(entry.getKey() + " = " + entry.getValue());
//				}
                onPostRequest(ctx, hashMap);
            }
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        try {
            writeAndFlushResponse(ctx, 404, "服务器错误\n" + cause.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
        ctx.close();
    }
}
